package compiller;

import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Logger;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * A test class to test dynamic compilation API.
 * 
 */
public class Compiler {

    /**
     * Does the required object initialization and compilation.
     */
    public boolean doCompilation(String name, String code) { 
	/* Creating dynamic java source code file object */
	SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(name,
		code);
	JavaFileObject javaFileObjects[] = new JavaFileObject[] { fileObject };

	JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
	StandardJavaFileManager stdFileManager = compiler
		.getStandardFileManager(null, Locale.getDefault(), null);

	/*
	 * Prepare a list of compilation units (java source code file objects)
	 * to input to compilation task
	 */
	Iterable<? extends JavaFileObject> compilationUnits = Arrays
		.asList(javaFileObjects);

	/* Prepare any compilation options to be used during compilation */
	// In this example, we are asking the compiler to place the output files
	// under bin folder.
	String[] compileOptions = new String[] { "-d", "bin" };
	Iterable<String> compilationOptionss = Arrays.asList(compileOptions);

	DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
	CompilationTask compilerTask = compiler.getTask(null, stdFileManager,
		diagnostics, compilationOptionss, null, compilationUnits);

	boolean status = compilerTask.call();

	if (!status) {// If compilation error occurs
	    /* Iterate through each compilation problem and print it */
	    for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
		System.out.format("Error on line %d in %s",
			diagnostic.getLineNumber(), diagnostic);
	    }
	}
	try {
	    stdFileManager.close();// Close the file manager
	} catch (IOException e) {
	    e.printStackTrace();
	}
	return status;
    }
}

/**
 * Creates a dynamic source code file object
 * 
 * This is an example of how we can prepare a dynamic java source code for
 * compilation. This class reads the java code from a string and prepares a
 * JavaFileObject
 * 
 */
class DynamicJavaSourceCodeObject extends SimpleJavaFileObject {
    private String qualifiedName;
    private String sourceCode;

    /**
     * Converts the name to an URI, as that is the format expected by
     * JavaFileObject
     * 
     * 
     * @param fully
     *            qualified name given to the class file
     * @param code
     *            the source code string
     */
    protected DynamicJavaSourceCodeObject(String name, String code) {
	super(URI.create("string:///" + name.replaceAll("\\.", "/")
		+ Kind.SOURCE.extension), Kind.SOURCE);
	this.qualifiedName = name;
	this.sourceCode = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors)
	    throws IOException {
	return sourceCode;
    }

    public String getQualifiedName() {
	return qualifiedName;
    }

    public void setQualifiedName(String qualifiedName) {
	this.qualifiedName = qualifiedName;
    }

    public String getSourceCode() {
	return sourceCode;
    }

    public void setSourceCode(String sourceCode) {
	this.sourceCode = sourceCode;
    }
}